﻿using System;
using System.Linq;
using System.Reflection.Emit;
using System.Xml.Serialization;
using System.IO;
using System.Data;
using System.Collections.Generic;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Sdk.Metadata;
using Microsoft.Crm.Sdk.Query;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.SdkTypeProxy.Metadata;
using TransactionServer.General_Classes;
using ConditionOperator = Microsoft.Crm.Sdk.Query.ConditionOperator;
using Connector = TransactionServer.General_Classes;
using System.Net;
using System.Text;

namespace TransactionServer.CRM4Activities
{

    public class CRM4Connector : Connector.ISystemConnector
    {
        public string connection;
        public object syncRoot = new object();
        public object syncRoot1 = new object();

        private CRM4EntityMetadataCache _entityCache;
        private CRM4EntityMetadataCache entityCache
        {
            get
            {
                lock (syncRoot)
                {
                    if (_entityCache == null)
                    {
                        _entityCache = new CRM4EntityMetadataCache(this);
                    }
                    return _entityCache;
                }
            }
        }


        public CRM4Connector(Dictionary<string, string> settings) : base (settings)
        {
        }

        public override Connector.Event getNextEvent()
        {
            var queryEvent = new QueryExpression()
                                 {
                                     ColumnSet = new AllColumns(),
                                     EntityName = "uds_integrationevent",
                                     PageInfo = new PagingInfo()
                                                    {
                                                        PageNumber = 1,
                                                        Count = 1
                                                    }
                                 };

            var request = new RetrieveMultipleRequest()
            {
                Query = queryEvent,
                ReturnDynamicEntities = true
            };

            var integrationEvents = ((RetrieveMultipleResponse)crmService.Execute(request)).BusinessEntityCollection.BusinessEntities;

            if (integrationEvents.Count > 0)
            {
                string xml = (string)((DynamicEntity)integrationEvents[0])["uds_event"];
                StringReader sr = new StringReader(xml);
                var serializer = new XmlSerializer(typeof(Connector.Event));
                crmService.Delete("uds_integrationevent", ((Key)((DynamicEntity)integrationEvents[0])["uds_integrationeventid"]).Value);
                return (Connector.Event)serializer.Deserialize(sr);
            }
            else
            {
                return null;
            }

            /*
            if (integrationEvents.Count > 0)
            {
                //Переделал под цикл, это нужно перепроверить
                
                foreach (DynamicEntity integrationEvent in integrationEvents)
                {
                    string xml = (string) integrationEvent["uds_event"];
                    StringReader sr = new StringReader(xml);
                    var serializer = new XmlSerializer(typeof (Connector.Event));
                    crmService.Delete("uds_integrationevent", (Guid) integrationEvent["uds_integrationeventid"]);
                    return (Connector.Event) serializer.Deserialize(sr);
                }
                
            }
            return null;
            */

        }

        private int? _languageCode = null;
        public int languageCode
        {
            get
            {
                lock (syncRoot)
                {
                    if (_languageCode == null)
                    {
                        string domainName = settings["domain"] + "\\" + settings["user"];
                        Guid userId = new Guid(lookupEntityByField("systemuser", "domainname", domainName));
                        ColumnSet columns = new ColumnSet(new string[] { "localeid" });
                        RetrieveUserSettingsSystemUserRequest request = new RetrieveUserSettingsSystemUserRequest()
                        {
                            EntityId = userId,
                            ColumnSet = columns,
                            ReturnDynamicEntities = true
                        };

                        DynamicEntity userSettings = (DynamicEntity)((RetrieveUserSettingsSystemUserResponse)crmService.Execute(request)).BusinessEntity;
                        _languageCode = ((CrmNumber)userSettings["localeid"]).Value;
                        return _languageCode.Value;
                    }
                    else
                    {
                        return _languageCode.Value;
                    }
                }
            }
        }

        private ServerConnection.Configuration _serverConfig;
        private ServerConnection.Configuration serverConfig
        {
            get
            {
                lock (syncRoot)
                {
                    if (_serverConfig == null)
                    {
                        lock (this)
                        {
                            ServerConnection serverConnect = new ServerConnection();
                            _serverConfig = serverConnect.GetServerConfiguration(settings);
                            return _serverConfig;
                        }
                    }
                    else
                    {
                        return _serverConfig;
                    }
                }
            }
        }

        private CrmService _crmService;
        public CrmService crmService
        {
            get
            {
                lock (syncRoot)
                {
                    if (_crmService == null)
                    {
                        lock (this)
                        {
                            ServicePointManager.ServerCertificateValidationCallback += delegate { return true; };

                            //ServerConnection serverConnect = new ServerConnection();
                            //ServerConnection.Configuration serverConfig = serverConnect.GetServerConfiguration(settings);
                            _crmService = new CrmService() 
                            {
                                Url = serverConfig.OrganizationUri.OriginalString,
                                Credentials = serverConfig.Credentials.Windows.ClientCredential
                            };
                            CrmAuthenticationToken token = new CrmAuthenticationToken();
                            token.OrganizationName = serverConfig.OrganizationName;
                            token.AuthenticationType = (int)Enum.Parse(typeof(AuthenticationType), serverConfig.EndpointType.ToString());
                            _crmService.CrmAuthenticationTokenValue = token;
                            /*
                            _crmService = new CrmService()
                                              {
                                                  Url = settings["url"]                                                 
                                              };

                            if (settings.ContainsKey("user") && !String.IsNullOrEmpty(settings["user"]))
                            {
                                _crmService.Credentials = new System.Net.NetworkCredential(settings["user"], settings["password"], settings["domain"]);
                            }
                            else
                            {
                                _crmService.Credentials = System.Net.CredentialCache.DefaultCredentials;
                            }
                            */


                            return _crmService;
                        }
                    }
                    else
                    {
                        return _crmService;
                    }
                }
            }
        }

        private MetadataService _metaCrmService;
        public MetadataService metaCrmService
        {
            get
            {
                lock (syncRoot)
                {
                    if (_metaCrmService == null)
                    {
                        lock (this)
                        {
                            //ServerConnection serverConnect = new ServerConnection();
                            //ServerConnection.Configuration serverConfig = serverConnect.GetServerConfiguration(settings);

                            _metaCrmService = new MetadataService()
                            {
                                Url = serverConfig.OrganizationMetadataUrl,
                                Credentials = serverConfig.Credentials.Windows.ClientCredential
                            };
                            CrmAuthenticationToken token = new CrmAuthenticationToken();
                            token.OrganizationName = serverConfig.OrganizationName;
                            token.AuthenticationType = (int)Enum.Parse(typeof(AuthenticationType), serverConfig.EndpointType.ToString());
                            _metaCrmService.CrmAuthenticationTokenValue = token;
                            _metaCrmService.UnsafeAuthenticatedConnectionSharing = true;
                            //throw new Exception(serverConfig.Credentials.Windows.ClientCredential.UserName + serverConfig.Credentials.Windows.ClientCredential.Password + serverConfig.Credentials.Windows.ClientCredential.Domain);
                            return _metaCrmService;
                        }
                    }
                    else
                    {
                        return _metaCrmService;
                    }
                }
            }
        }

        public override List<string> getAttributes(string entity)
        {
            List<string> res = new List<string>();

            try
            {
                foreach (AttributeMetadata emd in entityCache[entity].Attributes)
                {
                    res.Add(emd.LogicalName.ToLower());
                }
            }
            catch
            {
            }

            return res;
        }   

        //public int getAttributePicklistValue(string entity, string attribute, string optionset, string value, bool create)
        public int getAttributePicklistValue(string entity, string attribute, string value, bool create)
        {

            var response = (RetrieveAttributeResponse)metaCrmService.Execute(new RetrieveAttributeRequest()
            {
                EntityLogicalName = entity,
                LogicalName = attribute,
                RetrieveAsIfPublished = true
            });

            var options = ((PicklistAttributeMetadata)response.AttributeMetadata).Options.ToArray();

            var resultOptions = (from option in options where option.Label.UserLocLabel.Label == value select option).ToList();

            if (resultOptions.Count <= 0)
            {
                if (create)
                {
                    var newCrmLabel = new CrmLabel();
                    var label = new LocLabel {LanguageCode = new CrmNumber(languageCode), Label = value};
                    newCrmLabel.LocLabels = new LocLabel[] { label };

                    var request = new InsertOptionValueRequest()
                                      {
                                          Label = newCrmLabel

                                      };
                    string xml = string.Empty;
                    /*
                    if (!String.IsNullOrEmpty(optionset))
                    {
                        //Предположил, что вместо request.OptionSetName в 4ке используется request.Value 
                        request.Value = new CrmNumber(Convert.ToInt32(optionset));
                        xml = String.Format("<importexportxml><optionsets><optionset>{0}</optionset></optionsets></importexportxml>", optionset);
                    }
                    else
                    {
                        request.EntityLogicalName = entity;
                        request.AttributeLogicalName = attribute;
                        xml = String.Format("<importexportxml><entities><entity>{0}</entity></entities></importexportxml>", entity);
                    };
                    */
                    request.EntityLogicalName = entity;
                    request.AttributeLogicalName = attribute;
                    xml = String.Format("<importexportxml><entities><entity>{0}</entity></entities></importexportxml>", entity);

                    int result = ((InsertOptionValueResponse)metaCrmService.Execute(request)).NewOptionValue;

                    crmService.Execute(new PublishXmlRequest()
                        {
                            ParameterXml = xml
                        });

                    return result;
                }
                else
                {
                    return -1;
                }
            }
            else
            {
                return resultOptions[0].Value.Value;
            }

        }

        public string lookupEntityByField(string entity, string field, object value)
        {
            EntityMetadata emd = entityCache[entity];

            var result = String.Empty;

            var cs = new ColumnSet(new string[] { emd.PrimaryKey });

            var qbaEntity = new QueryByAttribute()
            {
                ColumnSet = cs,
                EntityName = entity,
                Attributes = new string[] {field},
                Values = new object[] {value}
             };
            

            var request = new RetrieveMultipleRequest()
            {
                Query = qbaEntity,
                ReturnDynamicEntities = true
            };

            var bec = ((RetrieveMultipleResponse) crmService.Execute(request)).BusinessEntityCollection;

            if (bec.BusinessEntities.Count > 0)
            {
                DynamicEntity de = (DynamicEntity)bec.BusinessEntities[0];
                result = ((Key)(de[emd.PrimaryKey])).Value.ToString();
            }            

            return result;
        }

        public override List<string> getEntities()
        {
            List<string> res = new List<string>();

               
            
            RetrieveAllEntitiesRequest request = new RetrieveAllEntitiesRequest();
            request.MetadataItems = MetadataItems.EntitiesOnly;
            RetrieveAllEntitiesResponse response = (RetrieveAllEntitiesResponse)metaCrmService.Execute(request);
            foreach (EntityMetadata emd in response.CrmMetadata)
            {
                
                res.Add(emd.LogicalName);
            }

            return res;
        }

        private String getEntityTypeCodeByName(string entityName)
        {
            String typeCode = String.Empty;
            var rerq = new RetrieveEntityRequest { EntityItems = EntityItems.EntityOnly, LogicalName = entityName };
            var rersp = (RetrieveEntityResponse)metaCrmService.Execute(rerq);
            typeCode = rersp.EntityMetadata.ObjectTypeCode.Value.ToString();
            return typeCode;
        }

        public String getLinkToEntity(Entity entity)
        {
            StringBuilder linkBuilder = new StringBuilder();
            String serviceUrl = serverConfig.OrganizationUri.OriginalString;
            linkBuilder.Append(serviceUrl.Substring(0, serviceUrl.IndexOf("MSCrmServices") - 1));
            linkBuilder.Append("/"+ serverConfig.OrganizationName);
            linkBuilder.Append("/userdefined/edit.aspx?id={");
            linkBuilder.Append(entity.Id);
            linkBuilder.Append("}&etc=");
            linkBuilder.Append(getEntityTypeCodeByName(entity.Name));
            return linkBuilder.ToString();
        }

        private AttributeMetadata getAttrByName(EntityMetadata emd, string attrName)
        {
            return (from amd in emd.Attributes where amd.LogicalName == attrName select amd).First();
        }

        private OneToManyMetadata getRelationshipByName(EntityMetadata emd, string attrName)
        {
            return (from amd in emd.ManyToOneRelationships where amd.ReferencingAttribute == attrName select amd).First();
        }

        public List<Connector.Entity> getObjects(Connector.Filter filter)
        {
            var result = new List<Connector.Entity>();

            var qeObjects = new QueryExpression() { EntityName = filter.entity };

            ColumnSet cs = new ColumnSet();
            foreach (Connector.CAttribute attribute in filter.attributes)
            {
                cs.AddColumn(attribute.name);
            }

            qeObjects.ColumnSet = cs;

            if (filter.conditions.Count > 0)
            {
                var feObjects = new FilterExpression() { FilterOperator = LogicalOperator.And };

                foreach (Connector.CCondition condition in filter.conditions)
                {
                    var ceObjects = new ConditionExpression()
                    {
                        AttributeName = condition.attribute,
                        Values = new object[] {condition.value}
                    };
                    

                    switch (condition.opr)
                    {
                        case Connector.ConditionOperator.Equal:
                            ceObjects.Operator = ConditionOperator.Equal;
                            break;
                        case Connector.ConditionOperator.Less:
                            ceObjects.Operator = ConditionOperator.LessThan;
                            break;
                        case Connector.ConditionOperator.LessEqual:
                            ceObjects.Operator = ConditionOperator.LessEqual;
                            break;
                        case Connector.ConditionOperator.More:
                            ceObjects.Operator = ConditionOperator.GreaterThan;
                            break;
                        case Connector.ConditionOperator.MoreEqual:
                            ceObjects.Operator = ConditionOperator.GreaterEqual;
                            break;
                        case Connector.ConditionOperator.NotEqual:
                            ceObjects.Operator = ConditionOperator.NotEqual;
                            break;
                        default:
                            break;
                    }

                    feObjects.Conditions.Add(ceObjects);
                }

                qeObjects.Criteria = feObjects;
            }

            var request = new RetrieveMultipleRequest()
            {
                Query = qeObjects,
                ReturnDynamicEntities = true
            };

            var response = (RetrieveMultipleResponse)crmService.Execute(request);

            var emd = entityCache[filter.entity];

            foreach (DynamicEntity de in response.BusinessEntityCollection.BusinessEntities)
            {
                var ent = new Connector.Entity()
                {
                    System = filter.connection,
                    //LogicalName переименовал в Name
                    Name = de.Name 
                };

                foreach (Property prop in de.Properties)
                {
                    AttributeMetadata amd = getAttrByName(emd, prop.Name);

                    if (amd != null)
                    {
                        
                        switch (amd.AttributeType.Value)
                        {
                            case AttributeType.Boolean:
                                ent[prop.Name] = ((CrmBooleanProperty)prop).Value.Value.ToString();
                                break;
                            case AttributeType.CalendarRules:
                                break;
                            case AttributeType.Customer:
                                ent.Add(prop.Name, ((CustomerProperty)prop).Value.Value.ToString());
                                break;
                            case AttributeType.DateTime:
                                ent.Add(prop.Name, ((CrmDateTimeProperty)prop).Value.Value.ToString());
                                break;
                            case AttributeType.Decimal:
                                ent.Add(prop.Name, ((CrmDecimalProperty)prop).Value.Value.ToString());
                                break;
                            case AttributeType.Float:
                                ent.Add(prop.Name, ((CrmFloatProperty)prop).Value.Value.ToString());
                                break;
                            case AttributeType.Integer:
                                ent.Add(prop.Name, ((CrmNumberProperty)prop).Value.Value.ToString());
                                break;
                            case AttributeType.Internal:
                                break;
                            case AttributeType.Lookup:
                                ent.Add(prop.Name, ((LookupProperty)prop).Value.Value.ToString());
                                break;
                            case AttributeType.Memo:
                                ent.Add(prop.Name, ((StringProperty)prop).Value);
                                break;
                            case AttributeType.Money:
                                ent.Add(prop.Name, ((CrmMoneyProperty)prop).Value.Value.ToString());
                                break;
                            case AttributeType.Owner:
                                ent.Add(prop.Name, ((OwnerProperty)prop).Value.Value.ToString());
                                break;
                            case AttributeType.PartyList:
                                break;
                            case AttributeType.Picklist:
                                ent.Add(prop.Name, ((PicklistProperty)prop).Value.Value.ToString());
                                break;
                            case AttributeType.PrimaryKey:
                                ent.Add(prop.Name, ((KeyProperty)prop).Value.Value.ToString());
                                ent.Id = ((KeyProperty)prop).Value.Value.ToString();
                                break;
                            case AttributeType.State:
                                ent.Add(prop.Name, ((StateProperty)prop).Value);
                                break;
                            case AttributeType.Status:
                                ent.Add(prop.Name, ((StatusProperty)prop).Value.Value.ToString());
                                break;
                            case AttributeType.String:
                                ent.Add(prop.Name, ((StringProperty)prop).Value);
                                break;
                            case AttributeType.UniqueIdentifier:
                                break;
                            case AttributeType.Virtual:
                                break;
                            default:
                                break;
                        }
                    }
                }

                result.Add(ent);
            }


            return result;
        }

        public Connector.Entity getEntityById(string systemName, string entityName, string entityId, string[] attributes)
        {
            var start = DateTime.Now;

            //переделал var de = crmService.Retrieve(entityName, new Guid(entityId), new ColumnSet(attributes))  под RetrieveRequest and Execute method
            TargetRetrieveDynamic target = new TargetRetrieveDynamic();
            target.EntityId =new Guid(entityId);
            target.EntityName = entityName;

            RetrieveRequest request = new RetrieveRequest();
            request.ColumnSet = new ColumnSet(attributes);
            request.ReturnDynamicEntities = true;
            request.Target = target;

            DynamicEntity de = (DynamicEntity)((RetrieveResponse)crmService.Execute(request)).BusinessEntity;

            var end = DateTime.Now;
            var span = end - start;
            Console.WriteLine("Retrieve {0}", span.TotalMilliseconds);

            Connector.Entity ent = new Connector.Entity(systemName, entityName, entityId);

            Guid id = Guid.Empty;

            EntityMetadata emd = entityCache[entityName];

            foreach (Property prop in de.Properties)
            {
                AttributeMetadata amd = getAttrByName(emd, prop.Name);

                if (amd != null)
                {
                    //                    ent[prop.Key] = prop.Value.ToString();
                    switch (amd.AttributeType.Value)
                    {
                        /*
                        case AttributeType.Lookup:
                            ent[prop.Name] = ((LookupProperty)prop).Value.ToString(); 
                            break;
                        case AttributeType.Owner:
                            ent[prop.Name] = ((OwnerProperty)prop).Value.ToString(); 
                            break;
                        case AttributeType.Customer:
                            ent[prop.Name] = ((CustomerProperty)prop).Value.ToString(); 
                            break;
                        case AttributeType.Money:
                            ent[prop.Name] = ((CrmMoneyProperty)prop).Value.ToString();
                            break;
                        case AttributeType.Picklist:
                            ent[prop.Name] = ((PicklistProperty)prop).Value.ToString();
                            break;
                        default:
                            ent[prop.Name] = prop.Name.ToString();
                            break;
                        */
                        case AttributeType.Boolean:
                            ent[prop.Name] = ((CrmBooleanProperty)prop).Value.Value.ToString();
                            break;
                        case AttributeType.CalendarRules:
                            break;
                        case AttributeType.Customer:
                            ent.Add(prop.Name, ((CustomerProperty)prop).Value.Value.ToString());
                            break;
                        case AttributeType.DateTime:
                            ent.Add(prop.Name, ((CrmDateTimeProperty)prop).Value.Value.ToString());
                            break;
                        case AttributeType.Decimal:
                            ent.Add(prop.Name, ((CrmDecimalProperty)prop).Value.Value.ToString());
                            break;
                        case AttributeType.Float:
                            ent.Add(prop.Name, ((CrmFloatProperty)prop).Value.Value.ToString());
                            break;
                        case AttributeType.Integer:
                            ent.Add(prop.Name, ((CrmNumberProperty)prop).Value.Value.ToString());
                            break;
                        case AttributeType.Internal:
                            break;
                        case AttributeType.Lookup:
                            ent.Add(prop.Name, ((LookupProperty)prop).Value.Value.ToString());
                            break;
                        case AttributeType.Memo:
                            ent.Add(prop.Name, ((StringProperty)prop).Value);
                            break;
                        case AttributeType.Money:
                            ent.Add(prop.Name, ((CrmMoneyProperty)prop).Value.Value.ToString());
                            break;
                        case AttributeType.Owner:
                            ent.Add(prop.Name, ((OwnerProperty)prop).Value.Value.ToString());
                            break;
                        case AttributeType.PartyList:
                            break;
                        case AttributeType.Picklist:
                            ent.Add(prop.Name, ((PicklistProperty)prop).Value.Value.ToString());
                            break;
                        case AttributeType.PrimaryKey:
                            ent.Add(prop.Name, ((KeyProperty)prop).Value.Value.ToString());
                            ent.Id = ((KeyProperty)prop).Value.Value.ToString();
                            break;
                        case AttributeType.State:
                            ent.Add(prop.Name, ((StateProperty)prop).Value);
                            break;
                        case AttributeType.Status:
                            ent.Add(prop.Name, ((StatusProperty)prop).Value.Value.ToString());
                            break;
                        case AttributeType.String:
                            ent.Add(prop.Name, ((StringProperty)prop).Value);
                            break;
                        case AttributeType.UniqueIdentifier:
                            break;
                        case AttributeType.Virtual:
                            break;
                        default:
                            break;
                    }
                }
            }

            return ent;
        }

        public DynamicEntity ConvertFrom(Connector.Entity entity)
        {
            var result = new DynamicEntity(entity.Name);
            var emd = entityCache[entity.Name];

            if (!String.IsNullOrEmpty(entity.Id))
            {
                result[emd.PrimaryKey] = new Guid(entity.Id);
            }

            foreach (KeyValuePair<string, object> item in entity)
            {
                AttributeMetadata amd = getAttrByName(emd, item.Key);
                string value = (string)item.Value;
                if (amd != null)
                {
                    try
                    {
                        switch (amd.AttributeType.Value)
                        {
                            case AttributeType.Boolean:
                                if (!String.IsNullOrEmpty(value))
                                    result.Properties.Add(new CrmBooleanProperty(item.Key, new CrmBoolean(Boolean.Parse(value))));
                                break;
                            case AttributeType.Customer:
                                if (!String.IsNullOrEmpty(value))
                                {
                                    var customer = new Customer()
                                    {
                                        Value = new Guid(value),
                                        name = "account"
                                    };

                                    result.Properties.Add(new CustomerProperty(item.Key,customer));
                                }
                                break;
                            case AttributeType.DateTime:
                                if (!String.IsNullOrEmpty(value))
                                    result.Properties.Add(new CrmDateTimeProperty(item.Key, new CrmDateTime(value)));
                                break;
                            case AttributeType.Decimal:
                                if (!String.IsNullOrEmpty(value))
                                    result.Properties.Add(new CrmDecimalProperty(item.Key, new CrmDecimal(Decimal.Parse(value))));
                                break;
                            case AttributeType.Float:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = new CrmDouble(Double.Parse(value));
                                break;
                            case AttributeType.Integer:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = int.Parse(value);
                                break;
                            case AttributeType.Lookup:
                                if (!String.IsNullOrEmpty(value))
                                {
                                    OneToManyMetadata rmd = getRelationshipByName(emd, item.Key);

                                    if (rmd != null)
                                    {
                                        var referencel = new Lookup()
                                        {
                                            Value = new Guid(value),
                                            name = rmd.ReferencedEntity
                                        };

                                        result[item.Key] = referencel;
                                    }
                                }
                                break;
                            case AttributeType.Memo:
                                result[item.Key] = (string)value;
                                break;
                            case AttributeType.Money:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = new CrmMoney(Decimal.Parse(value));
                                break;
                            case AttributeType.Owner:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = new Owner("systemuser", new Guid((string)value));
                                break;
                            case AttributeType.Picklist:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = new Picklist(int.Parse(value));
                                break;
                            case AttributeType.String:
                                result[item.Key] = (string)item.Value;
                                break;
                            default:
                                break;
                        }
                        /*
                        switch (amd.AttributeType.Value)
                        {
                            case AttributeType.Boolean:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = Boolean.Parse(value);
                                break;
                            case AttributeType.Customer:
                                if (!String.IsNullOrEmpty(value))
                                {
                                    var customer = new Customer()
                                    {
                                        Value = new Guid(value),
                                        name = "account"
                                    };

                                    result[item.Key] = customer;
                                }
                                break;
                            case AttributeType.DateTime:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = DateTime.Parse(value);
                                break;
                            case AttributeType.Decimal:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = Decimal.Parse(value);
                                break;
                            case AttributeType.Float:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = Double.Parse(value);
                                break;
                            case AttributeType.Integer:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = int.Parse(value);
                                break;
                            case AttributeType.Lookup:
                                if (!String.IsNullOrEmpty(value))
                                {
                                    OneToManyMetadata rmd = getRelationshipByName(emd, item.Key);

                                    if (rmd != null)
                                    {
                                        var referencel = new Lookup()
                                        {
                                            Value = new Guid(value),
                                            name = rmd.ReferencedEntity
                                        };

                                        result[item.Key] = referencel;
                                    }
                                }
                                break;
                            case AttributeType.Memo:
                                result[item.Key] = (string)value;
                                break;
                            case AttributeType.Money:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = new CrmMoney(Decimal.Parse(value));
                                break;
                            case AttributeType.Owner:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = new Owner("systemuser", new Guid((string)value));
                                break;
                            case AttributeType.Picklist:
                                if (!String.IsNullOrEmpty(value))
                                    result[item.Key] = new Picklist(int.Parse(value));
                                break;
                            case AttributeType.String:
                                result[item.Key] = (string)item.Value;
                                break;
                            default:
                                break;
                        }
                        */ 
                    }
                    catch(Exception ex)
                    {
                        throw new Exception(String.Format("Error parcing value {0} of attribute {1} of type {2}", value, item.Key, amd.AttributeType.Value));
                    }
                    
                }
            }

           

            return result;
        }

        public void LinkEntities(string entityFrom, Guid idFrom, string entityTo, Guid idTo, string relationshipName)
        {
           
            Moniker moniker1 = new Moniker();
            moniker1.Id = idFrom;
            moniker1.Name = entityFrom;

            Moniker moniker2 = new Moniker();
            moniker2.Id = idTo;
            moniker2.Name = entityTo;


            AssociateEntitiesRequest request = new AssociateEntitiesRequest();
            request.Moniker1 = moniker1;
            request.Moniker2 = moniker2;
            request.RelationshipName = relationshipName;

            crmService.Execute(request);
        }

        public void UnLinkEntities(string entityFrom, Guid idFrom, string entityTo, Guid idTo, string relationshipName)
        {

            Moniker moniker1 = new Moniker();
            moniker1.Id = idFrom;
            moniker1.Name = entityFrom;

            Moniker moniker2 = new Moniker();
            moniker2.Id = idTo;
            moniker2.Name = entityTo;


            DisassociateEntitiesRequest request = new DisassociateEntitiesRequest();
            request.Moniker1 = moniker1;
            request.Moniker2 = moniker2;
            request.RelationshipName = relationshipName;

            crmService.Execute(request);
        }

        public override DataTable getObjectList(string entityName)
        {
            var result = new DataTable();
            result.Columns.Add("objectid");
            result.Columns.Add("name");

            var mdAttributes = entityCache[entityName];
            var nameField = mdAttributes.PrimaryField;
            var keyField = mdAttributes.PrimaryKey;

            var csEntities = new ColumnSet();
            csEntities.AddColumns(nameField, keyField);

            var qeEntities = new QueryExpression()
            {
                EntityName = entityName,
                ColumnSet = csEntities
            };

            var requestEntities = new RetrieveMultipleRequest()
            {
                Query = qeEntities,
                ReturnDynamicEntities = true
            };

            var becEntities =
                ((RetrieveMultipleResponse) crmService.Execute(requestEntities)).BusinessEntityCollection.
                    BusinessEntities;

            foreach (DynamicEntity deEntity in becEntities)
            {
                var row = result.NewRow();
                row["objectid"] = ((Key)deEntity[keyField]).Value.ToString();
                if (deEntity.Properties.Contains(nameField))
                {
                    row["name"] = (string)deEntity[nameField];
                }
                result.Rows.Add(row);
            }

            return result;
        }

        public override HealthInfo CheckHealth()
        {
            var healthInfo = new HealthInfo()
            {
                ServiceName = GetType().FullName
            };

            try
            {
                var whoAmIResponse = ((WhoAmIResponse)crmService.Execute(new WhoAmIRequest()));
                healthInfo.Status = true;
            }
            catch (Exception exc)
            {
                close();
                healthInfo.Status = false;
                healthInfo.ErrorInfo = string.Format("{0}\n{1}", exc.Message, exc.StackTrace);
            }

            return healthInfo;
        }

        public override void close()
        {
            _crmService = null;
            GC.Collect();
        }
    }
}
